<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body>
  <script>
    // 如果出现循环引用，如下代码，在进行深拷贝就会报错，超出栈最大值
    let obj = {
      a: "dsf",
      age: 26,
      friends: {
        name: "likun",
        num: [1, 2, 3],
        age: 21,
        schools: { name: "lantian" },
      },
    };
    // let obj1 = {}
    // obj.obj1 = obj1
    // obj1.obj = obj
    let o = deepClone(obj); //报错
    console.log(o);
    // 更全面的深拷贝
    function deepClone(source, memory) {
      const isPrimitive = (value) => {
        return /Number|Boolean|String|Null|Undefined|Symbol|Function/.test(
          Object.prototype.toString.call(value),
        );
      };
      let result = null;

      memory || (memory = new WeakMap());
      // 原始数据类型及函数
      if (isPrimitive(source)) {
        console.log("current copy is primitive", source);
        result = source;
      }
      // 数组
      else if (Array.isArray(source)) {
        result = source.map((value) => deepClone(value, memory));
      }
      // 内置对象Date、Regex
      else if (Object.prototype.toString.call(source) === "[object Date]") {
        result = new Date(source);
      } else if (Object.prototype.toString.call(source) === "[object Regex]") {
        result = new RegExp(source);
      }
      // 内置对象Set、Map
      else if (Object.prototype.toString.call(source) === "[object Set]") {
        result = new Set();
        for (const value of source) {
          result.add(deepClone(value, memory));
        }
      } else if (Object.prototype.toString.call(source) === "[object Map]") {
        result = new Map();
        for (const [key, value] of source.entries()) {
          result.set(key, deepClone(value, memory));
        }
      }
      // 引用类型
      else {
        if (memory.has(source)) {
          result = memory.get(source);
        } else {
          result = Object.create(null);
          memory.set(source, result);
          Object.keys(source).forEach((key) => {
            const value = source[key];
            result[key] = deepClone(value, memory);
          });
        }
      }
      return result;
    }
    //深拷贝，考虑循环引用
    function deepClone1(obj, map = new WeakMap()) {
      if (obj == undefined || typeof obj !== "object") return obj;
      else if (obj instanceof Date) {
        return new Date(obj);
      } else if (obj instanceof RegExp) {
        return new RegExp(obj);
      } else {
        if (map.get(obj)) {
          return map.get(obj);
        }
      }
      // 下面这句话相当于 如果obj是对象 result就是一个新对象，如果obj是数组那人数聊天就是新数组
      let result = new obj.constructor();
      map.set(obj, result);
      for (var key in obj) {
        result[key] = deepClone1(obj[key], map);
      }
      return result;
    }
    // console.log(obj);
    let a = {
      a: "dsf",
      age: 26,
      friends: {
        name: "likun",
        num: [1, 2, 3],
        age: 21,
        schools: { name: "lantian" },
        obj2: {
          cs: 'ssss'
        }
      },
    };
    let obj2 = {}
    a.obj2 = obj2
    obj2.a = a
    let ob = deepClone1(a);
    let value = 1
    Object.defineProperty(window, 'aa', {
      get() {
        return value++
      }
    })
    if (aa === 1 && aa === 2 && aa === 3) {
      console.log('dddddddd');
    }
    var Single = function (name) {
      this.name = name
    }
    var getInstanse = function (name) {
      if (!this.instance) {
        this.instance = new Single(name)
      }
      return this.instance
    }

  </script>
</body>

</html>